unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Timer1: TTimer;
    Button2: TButton;
    Timer2: TTimer;

    procedure FormPaint(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);

    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Button2Click(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
    Bufmap: TBitmap;
    procedure PaintGrid;
    procedure DrawCell(X,Y: Integer);
  end;

const
  GRIDSIZE = 100;
  CELLSIZE = 5;
var
  Form1: TForm1;
  NewGrid, Grid: array[0..GRIDSIZE-1, 0..GRIDSIZE-1] of Integer;
  ClickDown: Boolean;
  Count: Integer;

implementation
{$R *.dfm}

function HasNeighbours(X, Y, Number: Integer): Boolean;
var
  X1, Y1, FX, FY, Count: INTEGER;
begin
  Count := 0;
  for X1 := X-1 to X+1 do
  begin
    FX := X1;
    if (FX < 0) or (FX >= GRIDSIZE) then
    begin
      continue;
    end;
    for Y1 := Y-1 to Y+1 do
    begin
      FY := Y1;
      if (FY < 0) or (FY >= GRIDSIZE) then
        continue;
      if (FX = X) and (FY = Y) then
        continue;
      if Grid[FX, FY] <> 0 then
        Inc(Count);
    end;
  end;
  Result := (Number = Count);
end;

function HasNewNeighbours(X, Y, Number: Integer): Boolean; overload;
var
  X1, Y1, FX, FY, Count: INTEGER;
begin
  Count := 0;
  for X1 := X-1 to X+1 do
  begin
    FX := X1;
    if (FX < 0) or (FX >= GRIDSIZE) then
      continue;
    for Y1 := Y-1 to Y+1 do
    begin
      FY := Y1;
      if (FY < 0) or (FY >= GRIDSIZE) then
        continue;
      if (FX = X) and (FY = Y) then
        continue;
      if Grid[FX,FY] = 32 then
        Inc(Count);
    end;
  end;
  Result := (Number = Count);
end;

procedure UpdateGrid;
var
  X, Y, I: Integer;
begin
  for X := 0 to GRIDSIZE-1 do
    for Y := 0 to GRIDSIZE-1 do
      NewGrid[X,Y] := Grid[X,Y];
  for X := 0 to GRIDSIZE-1 do
  begin
    for Y := 0 to GRIDSIZE-1 do
    begin
      // birth
      if Grid[X,Y] = 0 then begin
        if HasNewNeighbours(X, Y, 2) or HasNewNeighbours(X, Y, 4) then
        begin
          NewGrid[X,Y] := 32;
        end;
      end;
      // survival and aging
      if Grid[X,Y] <> 0 then
      begin
        {if HasNeighbours(X, Y, 3) or HasNeighbours(X, Y, 4) or
        HasNeighbours(X, Y, 5) then
          if Grid[X,Y] = 32 then
          NewGrid[X,Y] := 0     
        else   }
          Dec(NewGrid[X,Y]);
      end
    end;
  end;
  for X := 0 to GRIDSIZE-1 do
    for Y := 0 to GRIDSIZE-1 do
      Grid[X,Y] := NewGrid[X,Y];
end;

procedure TForm1.PaintGrid;
var
  X,Y: Integer;
begin
  for X := 0 to GRIDSIZE-1 do
  begin
    for Y := 0 to GRIDSIZE-1 do
    begin
      if Grid[X,Y] = 0 then
        Bufmap.Canvas.Brush.Color := clBlack
      else
        Bufmap.Canvas.Brush.Color := RGB(255, 256 - Grid[X,Y]*6, 0);
      Bufmap.Canvas.FillRect(Rect(X*CELLSIZE, Y*CELLSIZE,
        (X+1)*CELLSIZE,(Y+1)*CELLSIZE));
    end;
  end;
  Canvas.Draw(0, 0, Bufmap);
end;


procedure TForm1.FormPaint(Sender: TObject);
begin
  PaintGrid;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  X, Y, I: Integer;
begin
  I := GRIDSIZE div 2;
  for X := I - 4 to I + 4 do
    for Y := I - 4 to I + 4 do
      Grid[X,Y] := 32;
  Form1.PaintGrid;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Bufmap := TBitmap.Create;
  Bufmap.Width := GRIDSIZE*CELLSIZE;
  Bufmap.Height := GRIDSIZE*CELLSIZE;

 { Grid[50,50] := 32;
  Grid[50, 49] := 32;
  Grid[50, 51] := 32;
  if HasNeighbours(50, 50, 2) then
  Showmessage('true');    }
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  UpdateGrid;
  PaintGrid;
end;


procedure TForm1.DrawCell(X,Y: Integer);
var
  CellX, CellY: Integer;
begin
  CellX := X;
  CellY := Y;
  if (CellX < GRIDSIZE) and (CellY < GRIDSIZE) then
  begin
    Grid[CellX, CellY] := 32;
    Canvas.Brush.Color := RGB(Grid[CellX,CellY]*7, 0, 0);
    Canvas.FillRect(Rect(CellX*CELLSIZE, CellY*CELLSIZE,
        (CellX+1)*CELLSIZE,(CellY+1)*CELLSIZE));
  end;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);

begin
  if ClickDown then
    DrawCell(X div CELLSIZE, Y div CELLSIZE);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Timer1.Enabled := not Timer1.Enabled; 
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbRight then
  begin
    Timer1.Enabled := not Timer1.Enabled;
  {  if Timer1.Enabled then
      Form1.Color := clNavy
    else
      Form1.Color := clSilver;  }
  end
  else
  begin
    DrawCell(X div CELLSIZE, Y div CELLSIZE);
    ClickDown := True;
  end;
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ClickDown := False;
end;

end.
